﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data.Linq;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;

using System.Net.DnsToolkit.Serializer;
using System.Net.DnsToolkit.Packet;
using System.Net.DnsToolkit.Scanner.Helper;
using System.Net.DnsToolkit.Util;
using Ninject;
using System.Net.DnsToolkit.Configuration;

namespace System.Net.DnsToolkit.Scanner {
    public class ResponseProcessor {

        const int batchSize = 1000;
        const string ConnString = "System.Net.DnsToolkit.Scanner.Properties.Settings.RootScannerConnectionString1";

        //static int offset = 0;
        const int BufferSize = 512;
        static readonly byte[] buffer = new byte[BufferSize * batchSize];
        static IMessageReader<Stream> _messageReader;
        static IMessage _message;
        static IKernel _kernel;

        static ResponseProcessor() {

            _kernel = new StandardKernel(
                new DnsReaderStreamModule(),
                new DnsWriterJsonModule()
                );
            sp.CommandType = CommandType.StoredProcedure;
            sp.Parameters.Add("@arrIdHost", SqlDbType.Binary);

        }

        public static void Main(string[] argv) {
            Process();

        }

        public static void Process() {

            using (var db = new RootScannerDataContext()) {
                //db.Log = Console.Out;

                var loadOptions = new DataLoadOptions();
                loadOptions.LoadWith<Host>(h => h.IdHost);
                db.LoadOptions = loadOptions;
               
                var s = from h in db.Hosts
                        where h.Processed == false
                        select h.IdHost;


                for (int i = 0; i < db.GetHostCount(); i++) {

                    var hs = s.Skip(i * batchSize).Take(batchSize);
                    Console.WriteLine("Message {0} to {1}", i * batchSize, ((i+1)*batchSize)-1);

                    FillBuffer(hs, buffer);
                    int j = 0;
                    foreach (var idHost in hs) {

                        try {

                            int offset = j++ * BufferSize;
                            var mem = new MemoryStream(buffer, offset, BufferSize);
                            var reader = _kernel.Get<IMessageReader<System.IO.Stream>>();
                            bool read = reader.TryRead(mem, out _message);

                            if (!read) {
                                Console.WriteLine("Message unreadable {0}", idHost);
                            }

                            if (_message.Header.Id != 0x1337) {
                                Console.WriteLine("Header Id mismatch {0}, {1}", idHost, _message.Header.Id);
                                var writer = _kernel.Get<IMessageWriter<TextWriter>>();
                                writer.Write(Console.Out, _message);
                            }
                        } catch (Exception e) {
                            Console.WriteLine("Unexpected error at {0}, {1}", idHost, e.Message);
                        }
                    }
                }
                

            }

        }
        static readonly string connString = ConfigurationManager.ConnectionStrings[ConnString].ConnectionString;
        static readonly SqlCommand sp = new SqlCommand("rs_GetHostBinay");
        static readonly BinaryIntegerArray<int> ids = BinaryIntegerArrayFactory.CreateInt32();

        static void FillBuffer(IEnumerable<int> idHosts, byte[] buffer) {

            if (idHosts == null) {
                throw new ArgumentNullException("idHosts");
            }

            if (buffer == null) {
                throw new ArgumentNullException("buffer");
            }

            ids.Clear();
            foreach (var idHost in idHosts) { ids.Add(idHost); }

            Array.Clear(buffer, 0, buffer.Length);
            using (var conn = new SqlConnection(connString)) {
                conn.Open();
                sp.Parameters["@arrIdHost"].Value = ids.ToBinary();
                sp.Connection = conn;

                using (SqlDataReader reader = sp.ExecuteReader(CommandBehavior.SequentialAccess)) {

                    for (int offset = 0; reader.Read(); offset += BufferSize) {
                        reader.GetBytes(0, 0, buffer, offset, BufferSize);
                    }

                }
            }
        }

    }
}
